package Stana.hierarchicalClustering;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

//import org.jfree.data.Value;

import Stana.JavaDBFReaderTest;


public class AlgoHierarchicalClustering {

	private double maxQuantity =0;
	private double maxPrice =0;
	private String inputFile = "";
	private String outputFile = "";
	List<PriceQuantityItem> items;
	List<PriceQuantityCluster> clusters;
	public AlgoHierarchicalClustering(
			double maxQuantity,
			double maxPrice,
			String inputFile, 
			String outputFile) {
		this.inputFile = inputFile;
		this.outputFile = outputFile;
		items = new ArrayList<PriceQuantityItem>();
	// open the file and read
	try{
	  // Open the file that is the first 
	  // command line parameter
	  FileInputStream fstream = new FileInputStream(inputFile);
	  // Get the object of DataInputStream
	  DataInputStream in = new DataInputStream(fstream);
	  BufferedReader br = new BufferedReader(new InputStreamReader(in));
	  String strLine,dte,prodname;
	  float qty,prc;
	  //Read File Line By Line
	  int commaIndex = 0;
	  while ((strLine = br.readLine()) != null)  
	  {
		  for(int i=0;i<JavaDBFReaderTest.vectorquantity.size();i++)
		  {
			  dte=JavaDBFReaderTest.vectordte.get(i).toString();
			  qty=(Float) JavaDBFReaderTest.vectorquantity.get(i);
			  prc=(Float)JavaDBFReaderTest.vectorprc.get(i);
		      
		  StringTokenizer data = new StringTokenizer(strLine,",");
		  String prodName = "Hi";
		  String salesDate =dte;
		  float costQuantity = qty;
		  float price = prc;
		  
		 if (data.hasMoreElements()) {
				prodName = (String)data.nextElement();
				salesDate = (String)data.nextElement();
				costQuantity = Float.parseFloat((String)data.nextElement());
				price = Float.parseFloat((String)data.nextElement());
		  }
		  PriceQuantityItem item = new PriceQuantityItem(prodName, salesDate, costQuantity, price);
		  
		  System.out.println("Items:"+items.add(item));
	  }
    }
	  //Close the input stream
	  	in.close();
      } catch (Exception e){//Catch exception if any
		System.err.println("Error: " + e.getMessage());
	  }		
	}

	public AlgoHierarchicalClustering(String inputFile, String outputFile) {
		this.maxPrice = 45;
		this.maxQuantity =78;
		this.inputFile = inputFile;
		this.outputFile = outputFile;
		items = new ArrayList<PriceQuantityItem>();
		// open the file and read
		try {

			// Open the file that is the first 
			// command line parameter
			FileInputStream fstream = new FileInputStream(inputFile);
			// Get the object of DataInputStream
			DataInputStream in = new DataInputStream(fstream);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String strLine;
			//Read File Line By Line
			while ((strLine = br.readLine()) != null)   {
				  StringTokenizer data = new StringTokenizer(strLine);
				  String prodName = "";
				  String salesDate = "";
				  float costQuantity = 0.0f;
				  float price = 0.0f;

				  while (data.hasMoreElements()) {
						prodName = (String)data.nextElement();
						salesDate = (String)data.nextElement();
						costQuantity = Float.parseFloat((String)data.nextElement());
						price = Float.parseFloat((String)data.nextElement());
				  }
				  PriceQuantityItem item = new PriceQuantityItem(
						  prodName, salesDate, costQuantity, price);
				items.add(item);
			}
	  //Close the input stream
	  	in.close();
      } catch (Exception e){//Catch exception if any
		System.err.println("Error: " + e.getMessage());
	  }		
	}
	
	public AlgoHierarchicalClustering(float maxQuantity, float maxPrice) {
		this.maxQuantity = maxQuantity;
		this.maxPrice = maxPrice;
	}	

	public List<PriceQuantityCluster> runAlgorithmWithItems(List<PriceQuantityItem> items) {

		clusters = new ArrayList<PriceQuantityCluster>();

		// (1) Initialize all items as clusters
		for (PriceQuantityItem item : items) {
			PriceQuantityCluster cluster = new PriceQuantityCluster(item);
			clusters.add(cluster);
		}

		// (2) Loop to combine the two closest clusters into a bigger cluster
		// until no clusters can be combined.
		boolean wasAMerge = false;
		do {
			wasAMerge = mergeTheClosestCluster(clusters);
		} while (wasAMerge);

		// Calculate min and max
		for (PriceQuantityCluster cluster : clusters) {
			cluster.computeHigherAndLowerQuantity();
			cluster.computeHigherAndLowerPrice();
		}

		return clusters;
	}

	

	public List<PriceQuantityCluster>  getClusters() {
		return clusters;
	}
	public void  runAlgorithm() {
		clusters = new ArrayList<PriceQuantityCluster>();

		// (1) Initialize all items as clusters
		for (PriceQuantityItem item : items) {
			PriceQuantityItem data = item;
			PriceQuantityCluster cluster = new PriceQuantityCluster(data);
			clusters.add(cluster);
		}
		// (2) Loop to combine the two closest clusters into a bigger cluster
		// until no clusters can be combined.
		boolean wasAMerge = false;
		do {
			wasAMerge = mergeTheClosestCluster(clusters);
		} while (wasAMerge);

		// Calculate min and max
		for (PriceQuantityCluster cluster : clusters) {
			cluster.computeHigherAndLowerQuantity();
			cluster.computeHigherAndLowerPrice();
		}

		// write into the file
		try{
			// Create file 
		   FileWriter fstream = new FileWriter(outputFile);
		   BufferedWriter out = new BufferedWriter(fstream);
		   for(PriceQuantityCluster cluster : clusters) {
			   out.write(cluster.toString());
			   //Close the output stream
		   }
		   out.close();
	    } catch (Exception e){//Catch exception if any
		   System.err.println("Error: " + e.getMessage());
		}
	}

	public void printStats() {
		System.out.println("=============  Hierarchical Clustering =============");
		System.out.println("Successfully run the algorithm");
		System.out.println("===================================================");
	}
	private boolean mergeTheClosestCluster(List<PriceQuantityCluster> clusters) {
		PriceQuantityCluster clusterToMerge1 = null;
		PriceQuantityCluster clusterToMerge2 = null;
		double minClusterPrice = Integer.MAX_VALUE;
		double minClusterQuantity = Integer.MAX_VALUE;

//		// find the two closest cluster with price > threshold
//		for (int i = 0; i < clusters.size(); i++) {
//			for (int j = i + 1; j < clusters.size(); j++) {
//				double price = medianPrice(clusters.get(i),	clusters.get(j));
//				if (price < minClusterPrice && price < maxPrice) {
//					minClusterPrice = price;
//					clusterToMerge1 = clusters.get(i);
//					clusterToMerge2 = clusters.get(j);
//				}
//			}
//		}

		// find the two closest cluster with price > threshold
		for (int i = 0; i < clusters.size(); i++) {
			for (int j = i + 1; j < clusters.size(); j++) {
				double quantity = medianQuantity(clusters.get(i),
						clusters.get(j));
				if (quantity < minClusterQuantity && quantity < maxQuantity) {
					minClusterQuantity = quantity;
					clusterToMerge1 = clusters.get(i);
					clusterToMerge2 = clusters.get(j);
				}
			}
		}
		
		// if no close clusters were found, return false
		if (clusterToMerge1 == null) {
			return false;
		}

		// else, merge the two closest clusters
		clusterToMerge1.addItemsFromCluster(clusterToMerge2);
		clusterToMerge1.recomputeClusterMedianQuantity();
		clusterToMerge1.recomputeClusterMedianPrice();
		clusters.remove(clusterToMerge2);

		return true;
	}

	private double medianPrice(PriceQuantityCluster cluster1, PriceQuantityCluster cluster2) 
	{
		return Math.abs(cluster1.getMedianPrice() - cluster2.getMedianPrice());
	}
	private double medianQuantity(PriceQuantityCluster cluster1, PriceQuantityCluster cluster2) 
	{
		return Math.abs(cluster1.getMedianQuantity() - cluster2.getMedianQuantity());
	}
	public static void main(String []aa)
	{
		
	}

}
